package baiqitun.stupro.subject.service.impl;

import baiqitun.stupro.common.exception.enums.support.StuproExceptionEnum;
import baiqitun.stupro.common.constant.SysConstant;
import baiqitun.stupro.common.exception.enums.support.ExistedExceptionEnum;
import baiqitun.stupro.common.exception.enums.support.NotFoundExceptionEnum;
import baiqitun.stupro.common.exception.support.ExistedException;
import baiqitun.stupro.common.exception.support.NotFoundException;
import baiqitun.stupro.common.exception.StuproException;
import baiqitun.stupro.common.model.TreeModel;
import baiqitun.stupro.common.model.vo.TreeNodeVo;
import baiqitun.stupro.common.service.TreeNodeVoService;
import baiqitun.stupro.common.service.support.MyServiceImpl;
import baiqitun.stupro.security.entity.SysDepart;
import baiqitun.stupro.security.service.SysDepartService;
import baiqitun.stupro.subject.entity.SysSubject;
import baiqitun.stupro.subject.mapper.SysSubjectMapper;
import baiqitun.stupro.subject.service.SysSubjectService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotBlank;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 科目表（专业方向表） 服务实现类
 * </p>
 *
 * @author kedaji
 * @since 2020-04-01
 */
@Service
public class SysSubjectServiceImpl extends MyServiceImpl<SysSubjectMapper, SysSubject> implements SysSubjectService {
    @Autowired
    private TreeNodeVoService treeNodeVoService;
    @Autowired
    private SysDepartService sysDepartService;

    @Cacheable
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public List<TreeModel<TreeNodeVo>> getRootTrees() {
        LinkedList<TreeModel<TreeNodeVo>> trees = new LinkedList<>();
        QueryWrapper<SysSubject> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("parent_id");
        List<SysSubject> departs = list(queryWrapper);
        for (SysSubject tmpDepart : departs){
            TreeModel<TreeNodeVo> tree = getTreeById(tmpDepart.getId());
            trees.add(tree);
        }
        return trees;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(@Validated() SysSubject subject) {
        checkExisted(subject.getName(),subject.getParentId(), subject.getId());
        return super.save(subject);
    }

    @CacheEvict
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeById(@NotBlank(message = "科目id不能为空") String id,
                              @NotBlank(message = SysConstant.ER_UPDATE_BY_CANNOT_NULL) String updateBy) {
        checkExisted(id, new ExistedException(ExistedExceptionEnum.SUBJECT_EXISTED));
        SysSubject subject = new SysSubject();
        subject.setId(id).setUpdateBy(updateBy);
        updateById(subject);
        return super.removeById(id);
    }

    /**
     * 创建一个系
     * 每个系都会自带顶级科目
     * @param depart 部门
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveRootDepart(@Validated() SysDepart depart) {
        sysDepartService.saveRoot(depart);
        SysSubject defaultSubject = new SysSubject();
        defaultSubject.setName(depart.getName()).setDepartId(depart.getId()).setCreateBy(depart.getCreateBy());
        super.save(defaultSubject);
    }

    @Override
    public SysSubject getDefaultSubjectByRootDepart(String departId) {
        SysDepart depart = sysDepartService.getExistedEntity(departId, new NotFoundException(NotFoundExceptionEnum.DEPART_NOT_FOUND));
        if (StringUtils.isNotBlank(depart.getParentId())){
            throw new StuproException(StuproExceptionEnum.ILLEGAL_PARAMETER).put(SysDepart.class,"id", departId);
        }
        SysSubject querySubject = new SysSubject();
        querySubject.setDepartId(departId);
        return getOne(new QueryWrapper<>(querySubject));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateById(@Validated() SysSubject subject) {
        SysSubject result = getById(subject.getId());
        if (result == null){
            throw new NotFoundException(NotFoundExceptionEnum.SUBJECT_NOT_FOUND).put(SysSubject.class,"id",subject.getId());
        }
        checkExistedForUpdate(subject.getId(), subject.getParentId(), subject.getName());
        return super.updateById(subject);
    }

    private TreeModel<TreeNodeVo> getTreeById(String id){
        return treeNodeVoService.getTree(id, "stupro_subject");
    }

    private void checkExisted(String name, String parentId, String departId){
        SysSubject querySubject = new SysSubject();
        querySubject.setName(name).setParentId(parentId).setDepartId(departId);
        int count = count(new QueryWrapper<>(querySubject));
        if (count > 0){
            throw new ExistedException(ExistedExceptionEnum.SUBJECT_EXISTED).put(SysDepart.class,"name", name);
        }
    }

    private void checkExistedForUpdate(String id, String parentId, String name){
        SysSubject querySubject = new SysSubject();
        querySubject.setName(name).setParentId(parentId);
        int count = count(new QueryWrapper<>(querySubject).ne("id", id));
        if (count > 0){
            throw new ExistedException(ExistedExceptionEnum.SUBJECT_EXISTED)
                    .put(SysSubject.class, "parentId", parentId)
                    .put(SysSubject.class, "name", name);
        }
    }
}
